#pragma once

//C++头文件
#include <string>
#include <iostream>
#include <map>
#include <sstream>
#include <fstream>

//C语言库
#include <cstdlib>
//系统头文件
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>

//自研库
#include "SimpleThreadPool.hpp"

//全局变量
const std::string kServerRoot("./www");     //根目录
constexpr size_t kThreadPoolNum = 10;       //线程池的线程数量

//创建SimpleHTTPServer类
class SimpleHTTPServer {
    
public:
    //构造函数
    SimpleHTTPServer(int port = 8080, const std::string& root_dir = kServerRoot)
    :_port(port), _isrunning(false), _root_dir(root_dir), _threadPool(kThreadPoolNum){}

    //析构函数
    ~SimpleHTTPServer(){
        Stop();
    }
    
    //服务器启动：创建套接字、TCP监听请求
    bool Start(){
        std::cout << "=== Simple HTTP Server ===" << std::endl;
        std::cout << "启动服务器 端口: " << _port << std::endl;
        std::cout << "文档根目录: " << _root_dir << std::endl;

        //创建套接字
        _server_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(_server_fd < 0){
            std::cerr << "socket failed!" << std::endl;
            return false;
        }

        //绑定
        struct sockaddr_in serverSockaddr;
        serverSockaddr.sin_family = AF_INET;
        serverSockaddr.sin_addr.s_addr = INADDR_ANY;
        serverSockaddr.sin_port = htons(_port);
        if(bind(_server_fd, (struct sockaddr*)&serverSockaddr, sizeof(serverSockaddr)) < 0){
            std::cerr << "bind failed" << std::endl;
            close(_server_fd);
            return false;
        }

        //监听
        if(listen(_server_fd, 10) < 0){
            std::cerr << "listen failed" << std::endl;
            close(_server_fd);
            return false;
        }
        
        //修改运行标志
        _isrunning = true;
        std::cout << "服务器启动成功!" << std::endl;
        
        //输出启动成功信息
        char serverIP[INET_ADDRSTRLEN] = {0};
        inet_ntop(AF_INET, &serverSockaddr.sin_addr, serverIP, INET_ADDRSTRLEN);
        std::cout << "访问地址: http://" << serverIP << ":" << _port << std::endl;

        std::cout << "服务目录: " << _root_dir << std::endl;
        std::cout << "按 Ctrl+C 停止服务器\n" << std::endl;
        
        //开始运行程序
        while(_isrunning){
            struct sockaddr_in clientSockaddr;
            socklen_t clientLen = sizeof(clientSockaddr);

            //Aceept客户端
            int client_fd = accept(_server_fd, (struct sockaddr*)&clientSockaddr, &clientLen);
            if(client_fd < 0){
                if(!_isrunning){
                    break;
                }
                continue;
            }

            //获取客户端的IP
            char clientIP[INET_ADDRSTRLEN] ={0};
            inet_ntop(AF_INET, &clientSockaddr.sin_addr, clientIP, sizeof(clientIP));

            //分发任务给线程池
            _threadPool.Enqueue([this](int client_fd, const std::string& clientIP){
                ClientHandler(client_fd, clientIP); }, client_fd, clientIP);
        }

        return true;
    }

    //服务器停止函数
    void Stop(){
        if(_isrunning){
            _isrunning = false;
            close(_server_fd);
            std::cout << "\n服务器成功关闭！" << std::endl;
        }
    }

private:
    int _port;
    std::string _root_dir;
    bool _isrunning;
    int _server_fd;
    SimpleThreadPool _threadPool;
private:

    //线程工作方法
    void ClientHandler(int client_fd, const std::string client_IP){
        //创建信息储存数组
        std::vector<char> buffer(10 * 1024);

        while(true){
            //接受信息
            ssize_t recvBytes = recv(client_fd, buffer.data(), buffer.size() - 1, 0);            
            if(recvBytes < 0){
                std::cerr << "recv failed!" << std::endl;
                break;
            }else if(recvBytes == 0){
                std::cout << "客服端：" << client_IP << "断开连接！" << std::endl;
                break;
            }
            buffer[recvBytes] = '\0';

            std::string request(buffer.data(), recvBytes);
            std::cout << "收到来自 " << client_IP << " 的请求" << std::endl;

            //解析请求头
            HTTPRequest parsedRequest = ParseRequest(request);

            //生成HTTP响应
            std::string response = generateResponse(parsedRequest);

            //发送响应
            send(client_fd, response.c_str(), response.size(), 0);
        }
        close(client_fd);
    }

    //HTTP请求消息体
    typedef struct HTTPRequest{
        std::string method;     //请求方法
        std::string path;       //请求路径
        std::string version;    //HTTP协议版本
        std::map<std::string, std::string> header;     //请求头
        std::string body;       //请求体
    }HTTPRequest;
    //解析请求
    HTTPRequest ParseRequest(const std::string& request){
        HTTPRequest req;
        std::istringstream iss(request);
        std::string line;
        
        //处理请求行
        if(std::getline(iss, line)){
            //获取第一行的请求行，并且初始化req
            std::istringstream line_stream(line);
            line_stream >> req.method >> req.path >> req.version;
            
            //取出\r\n
            if(!req.version.empty() && req.version.back() == '\r'){
                req.version.pop_back();
            }
        }

        //处理请求头
        while(std::getline(iss, line) && line != "\r" && !line.empty()){
            size_t colonPos = line.find(':');
            if(colonPos == std::string::npos){
                continue;
            }
            std::string key = line.substr(0, colonPos);
            std::string value = line.substr(colonPos + 1);
            
            //删除value前面的空格以及制表符
            value.erase(0, value.find_first_not_of(" \t"));
            if(!value.empty() && value.back() == '\r'){
                value.pop_back();
            }
            
            //加入顺序map中
            req.header[key] = value;
        }

        //解析正文
        while(std::getline(iss, line)){
            req.body += (line += '\n');
        }
        if(!req.body.empty() && req.body.back() == '\r'){
            req.body.pop_back();
        }

        return req;
    }

    //生成HTTP响应
    std::string generateResponse(const HTTPRequest& parsedRequest){
        //仅仅支持GET方法
        if(parsedRequest.method != "GET"){
            return create_error_response(405, "Method Not Allowed", _root_dir + "/405.html");
        }

        //处理GET方法
        //处理路径
        std::string fullPath = parsedRequest.path == "/" ?
            _root_dir + "/index.html" : _root_dir + parsedRequest.path;

        std::ifstream fileOpen(fullPath, std::ios::binary);
        //打开失败，返回404
        if(!fileOpen.is_open()){
            return create_error_response(404, "Not Found", _root_dir + "/404.html");
        }

        //打开成功，返回页面
        std::string content{std::istreambuf_iterator<char>(fileOpen), std::istreambuf_iterator<char>()};
        fileOpen.close();

        // 构建HTTP响应
        std::ostringstream response;
        response << "HTTP/1.1 200 OK\r\n";
        // response << "Content-Type: " << mime_type << "\r\n";
        response << "Content-Length: " << content.size() << "\r\n";
        response << "Connection: close\r\n";
        response << "Server: SimpleHTTPServer/1.0\r\n";
        response << "\r\n";  // 空行分隔头部和内容
        response << content;
        
        return response.str();
    }

    // 创建错误响应
    std::string create_error_response(int status_code, const std::string& status_text
        , const std::string& file_path) {
        std::ostringstream response;
        std::string content;

        //获取405文件的全部内容
        //打开文件
        std::ifstream file405(file_path, std::ios::binary);
        if(!file405.is_open()){
            std::cerr << file_path << " open failed!" << std::endl;
            content = "<html><body><h1>" + std::to_string(status_code) + " " + status_text + "</h1></body></html>";
        }else{
            content = {std::istreambuf_iterator<char>(file405), std::istreambuf_iterator<char>()};
        }
        //读取全部的信息
        file405.close();

        response << "HTTP/1.1 " << status_code << " " << status_text << "\r\n";
        response << "Content-Type: text/html\r\n";
        response << "Content-Length: " << content.size() << "\r\n";
        response << "Connection: close\r\n";
        response << "Server: SimpleHTTPServer/1.0\r\n";
        response << "\r\n";
        response << content;
        
        return response.str();
    }
};